<template>
    <div class="tree-select" :style="{'height': height}">
        <div class="tree-select__main" v-show="treeNodes && treeNodes.length">
            <recycle-scroller 
                ref="scroller"
                size-field="height"
                :style="{'height': '100%'}"
                :item-size="null"
                :min-item-size="0"
                :items="treeNodes"
                :key-field="idKey"
            >
                <template slot-scope="{item, index}">
                    <tree-select-node
                        :key="item[idKey]"
                        :node="item"
                        :index="index"
                        :label-key="labelKey"
                        :item-height="itemHeight"
                        :selected="currentNodeId === item[idKey]"
                        @expand="handleExpandNode"
                        @collapse="handleCollapseNode"
                        @click="handleNodeClick"
                        @dblclick="handleNodeDblClick"
                    >
                        <slot slot-scope="scope" v-bind="scope"></slot>
                        <template slot="addon" slot-scope="scope">
                            <slot name="addon" v-bind="scope"></slot>
                        </template>
                    </tree-select-node>
                </template>
            </recycle-scroller>
        </div>
        <slot name="empty" v-if="!loading && (!treeNodes || !treeNodes.length)">
            <div class="tree-select__empty">暂无数据</div>
        </slot>
        <div class="tree-select__loading" v-if="loading">
            <tree-select-loading></tree-select-loading>
        </div>
    </div>
</template>
<script>
import Vue from 'vue'
import TreeSelectNode from './tree-select-node'
import VueVirtualScroller, { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import TreeSelectStore from './tree-select-store' 
import TreeSelectLoading from './tree-select-loading.vue'

Vue.use(VueVirtualScroller, {
    itemsLimit: Infinity
})

export default {
    name: 'TreeSelect',
    components: {
        TreeSelectNode,
        RecycleScroller,
        TreeSelectLoading
    },
    props: {
        data: {
            type: Array,
            default: () => []
        },
        loading: {
            type: Boolean
        },
        height: {
            type: String,
            default: '100%'
        },
        itemHeight: {
            type: Number,
            default: 24
        },
        idKey: {
            type: String,
            default: 'id'
        },
        labelKey: {
            type: String,
            default: 'label'
        },
        childrenKey: {
            type: String,
            default: 'children'
        },
        defaultExpandLevel: {
            type: Number
        },
        defaultExpandKeys: {
            type: Array
        },
        filterMethod: {
            type: Function
        },
        current: {
            type: [String, Number]
        }
    },
    watch: {
        data () {
            this.handleDataChange()
        }
    },
    created () {
        this.store = new TreeSelectStore({
            data: this.data,
            idKey: this.idKey,
            itemHeight: this.itemHeight,
            childrenKey: this.childrenKey,
            expandLevel: this.defaultExpandLevel,
            expandKeys: this.defaultExpandKeys,
            current: this.current,
            filterMethod: this.filterMethod,
            onCurrent: this.handleCurrentChange
        })
    },
    mounted () {
        this.$watch(() => {
            return this.$refs.scroller.ready
        }, () => {
            this.$nextTick(() => {
                this.scrollTo(this.currentNodeId)
            })
        })
    },
    computed: {
        treeNodes () {
            return this.store.props.nodes
        },
        currentNodeId () {
            return this.store.props.currentId
        }
    },
    methods: {
        handleDataChange () {
            this.store.setData(this.data)
        },
        handleExpandNode ({ node }) {
            this.store.expandNode(node)
        },
        handleCollapseNode ({ node }) {
            this.store.collapseNode(node)
        },
        handleNodeClick ({ node }) {
            this.store.setCurrentNodeId(node[this.idKey])
        },
        handleNodeDblClick ({ node }) {
            this.$emit('node-dblclick', {
                node
            })
        },
        filter (keyword) {
            this.store.filter(keyword)
        },
        handleCurrentChange ({ node }) {
            this.$emit('current', {
                node
            })
        },
        insertNode (data, parentNode) {
            this.store.insertNode(data, parentNode)
        },
        removeNode (node) {
            this.store.removeNode(node)
        },
        scrollTo (node) {
            const index = this.store.getNodeIndex(node)
            if (index < 0) {
                return
            }
            this.store.expandNode(this.store.getParentNode(node))
            this.$refs.scroller && this.$refs.scroller.scrollToItem(index)
        }
    }
}
</script>
<style>
.tree-select{
    overflow: auto;
    position: relative;
}
.tree-select__main{
    height: 100%;
}
.tree-select__empty{
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    color: #999;
}
.tree-select__loading{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}
</style>